package com.googlecode.accurev2disk;

import java.awt.print.Printable;
import java.io.BufferedReader;
import java.io.File;

public class AccurevToDisk {

	/**
	 * @param args
	 */
	public static void main(String[] args) {

	//Command Line Interface
		//cli
		CliBuilder cl = new CliBuilder()
		//help
		cl.h(longOpt:'help', 'Show usage information and quit')
		//storepath
		cl.p(argName:'path', longOpt:'path', args:1,required:true,'Directory to store the files at,REQUIRED')
		//log or not
		cl.l(argName:'log', longOpt:'log', args:0, required:false, 'Create a logfile or not')
		//basic stream name
		cl.b(argName:'basic', longOpt:'basic', args:1, required:true, 'The Stream to export')
		//temporary stream names

		cl.t(argName:'temp', longOpt:'temp', args:2, required:true, 'The first and second temporary Stream')

		//parsing CLI commands
		def opt = cl.parse(args)
		
		//print parameters
		println "path: "+opt.p
		println "log: "+opt.l
		println "basic: "+opt.b
		println "temp1: "+opt.ts[0]
        println "temp2: "+opt.ts[1]
		                                		                    
		//storepath

		File path = new File(opt.p)
		path.mkdirs()
		//logging on or off
		boolean logging = opt.l
		//basic Stream Name

		AccurevStream basic = new AccurevStream(opt.b)

		//temporary Stream Names
		AccurevStream temp1 = new AccurevStream(opt.ts[0], basic, 1)
		AccurevStream temp2 = new AccurevStream(opt.ts[1], basic, 1)


	//create Streams in Accurev
		basic.createInAccurev()
		temp1.createInAccurev()
		temp2.createInAccurev()
		
		
	//create Files
		String sep = System.getProperty("file.separator")

		//logfile
		File log
		if(logging){
			log = new File("${path}${sep}log.txt")
			log.append("\r\nData for Depot ${basic.getName()}\r\n")
		}
		//difference file
		File diff = new File(path.getPath() + "${sep}diff.txt")
		diff.write ""
		//history files
		File hist = new File(path.getPath() + "${sep}hist.txt")
		
		
		//		initiate AccurevToDisk
		AccurevToDisk a2d	= new AccurevToDisk()	
		


		// temporary String for writing and reading files
		String text	

		// for time measurement
		long start, stop
		//measure time
		start = System.currentTimeMillis()
		
		
		//calculate the history and save it to the file
		String history = basic.calculateHistory()
		hist.write history

		//parse the history to transaction Objects
		ParseTransactions pT = new ParseTransactions()
		AccurevTransaction[] transactions = pT.parseTransactionsWithVersions(hist)

		//calculate Diffs and populate each transaction
		transactions.each{

			int i = Integer.parseInt(it.id)
			
			//the first transaction can not be compared
			if(i > 1){
				//change the temporary Streams
				temp1.change(basic, i)
				temp2.change(basic, i-1)
				
				//write the diff-results to the file
				text ="\r\n" + it.toString() + "\r\n"
				text += temp2.calculateDiff(temp1)
				diff.append(text)
				
				//populate the Transaction
				a2d.populateTransaction(temp1, basic, it, path)
				
			}
		}

		stop = System.currentTimeMillis()
		
		if(logging){
		log.append "Time to calculate differences for every transaction: " + (stop - start)/1000 + "s.\r\n"
		}
		
		println "end"
		
		//		populateAll
//		start = System.currentTimeMillis()
//		a2d.populateAll(temp1, basic, 1, 4, path)
//		stop = System.currentTimeMillis()
//		log.append "Time to populate complete depot for every transaction: " + (stop - start)/1000 + "s.\r\n"

			
		//	populate 1 Transact
//			start = System.currentTimeMillis()
//			temp1.change(basic, 4)
//			temp1.populateTo(path)
//			stop = System.currentTimeMillis()
//			log.append "Time to populate 1 transaction: " + (stop - start)/1000 + "s.\r\n"
		
		//		history command
//		File hist = new File(path.getPath() + "\\hist.xml")
//		
//		start = System.currentTimeMillis()
//		text = basic.calculateHistory()
//		stop = System.currentTimeMillis()
//		log.append "calculate History needed " + (stop - start)/1000 + "s.\r\n"
//		
//		hist.write(text)

	}

	public void calculateAndPopulate(){
		
	}

	
	/**
	 * populates only the changed files of the Transactions
	 * @param temp the temporary Stream to work on
	 * @param basic the Stream to populate its history
	 * @param transactions the transactions generated by hist command and parsed from xml to AccurevTransactions
	 * @param storepath path where to store the files (transaction Numbers added as new directory)
	 * @return a String with the Information of every populated Transaction
	 */
	public void populateTransactions(AccurevStream temp, AccurevStream basic, Integer[] transactions, File storepath){

		// create a Directory for every transaction and populate only the changed files at this transaction number
		transactions.each{

			//create a timebased tempstream from the basicstream at the actual transaction number
			temp.change(basic, it)
			temp.populateTo(storepath)				
		}

	}

	/**
	 * populates only the changed files of the Transactions
	 * @param temp the temporary Stream to work on
	 * @param basic the Stream to populate its history
	 * @param transactions the transactions generated by hist command and parsed from xml to AccurevTransactions
	 * @param storepath path where to store the files (transaction Numbers added as new directory)
	 * @return a String with the Information of every populated Transaction
	 */
	public String populateTransactions(AccurevStream temp, AccurevStream basic, AccurevTransaction[] transactions, File storepath){

		def String result = ""
			String sep = System.getProperty("file.separator")

		// create a Directory for every transaction and populate only the changed files at this transaction number
		transactions.each{

			//new directory
			File path = new File(storepath.getPath() + "${sep}${it.id}")
			path.mkdirs()
			//create a timebased tempstream from the basicstream at the actual transaction number
			temp.change(basic, Integer.parseInt(it.id))
			
			//read the files pathname from every 'version' in the transaction, divided by whitespace, to a String
			def versionsFile = new File(storepath.getPath() + "${sep}versions.txt")
			versionsFile.write ""
			String version =""
				
			it.versions.each{  
				version +="${it.path.substring(1)}\r\n"
				println "${it.path}"
			}

			versionsFile.write version

			temp.populateFilesTo(path, versionsFile)

			//ad transactioninfo to the resultString
			result += it.toString()
			result += "\r\n\r\n"
			
		}
		return result
	}

	/**
	 * populates only the changed files of the Transaction
	 * @param temp the temporary Stream to work on
	 * @param basic the Stream to populate its history
	 * @param transaction the transaction generated by hist command and parsed from xml to AccurevTransactions
	 * @param storepath path where to store the files (transaction Number added as new directory)
	 */
	public void populateTransaction(AccurevStream temp, AccurevStream basic, AccurevTransaction transaction, File storepath){

		String sep = System.getProperty("file.separator")
		def int id = Integer.parseInt(transaction.id)
		// create a Directory for every transaction and populate only the changed files at this transaction number

			//new directory
			File path = new File(storepath.getPath() + "${sep}${id}")
			path.mkdirs()

			
			//read the files pathname from every 'version' in the transaction, divided by whitespace, to a String
			def versionsFile = new File(storepath.getPath() + "${sep}versions.txt")
			versionsFile.write ""
			String version =""
				
			transaction.versions.each{  
				//don't try to populate deleted files
			
				if( !(it.stat(temp).contains("no such elem")) )
					version +="${it.path.substring(1)}\r\n"
				}
		
			versionsFile.write version

			temp.populateFilesTo(path, versionsFile)
	}

	

	/**
	 * populates only the Transactions where files were changed
	 * @param temp the temporary Stream to work on
	 * @param basic the Stream to populate its history
	 * @param transactions the transactions generated by hist command and parsed from xml to AccurevTransactions
	 * @param storepath path where to store the files (transaction Numbers added as new directory)
	 * @return a String with the Information of every populated Transaction
	 */
	public String populateFullTransactions(AccurevStream temp, AccurevStream basic, AccurevTransaction[] transactions, File storepath){

		def String result = ""

		// create a Directory for every transaction and populate only the changed files at this transaction number
		transactions.each{

			//create a timebased tempstream from the basicstream at the actual transaction number
			temp.change(basic, Integer.parseInt(it.id))
			temp.populateTo(storepath)
			
			//ad transactioninfo to the resultString
			result += it.toString()
			result += "\r\n\r\n"
			
		}
		return result
	}

	/**
	 * @param basic
	 * @param temp1
	 * @param temp2
	 * @param transactions
	 * @return
	 */
	public String calculateTransactionsDiff(AccurevStream basic, AccurevStream temp1, AccurevStream temp2, AccurevTransaction[] transactions){

		def String result = ""			

		// create a Directory for every transaction and populate only the changed files at this transaction number
		transactions.each{
			int i = Integer.parseInt(it.id)


			//create a timebased tempstream from the basicstream at the actual transaction number
			if (it != transactions[0]){
			temp1.change(basic, i)
			temp2.change(basic, i-1)
			result += it.toString() + "\r\n"
			result += temp2.calculateDiff(temp1)
			
			} 
			
			//ad transactioninfo to the resultString
			
			result += "\r\n\r\n"
			
		}
		return result
	}


	
	/** calculates the Difference from the given Transaction to its predecessor using accurev diff command
	 * @param basic 
	 * @param temp1
	 * @param temp2
	 * @param transaction 
	 * @return header with information about the Transaction, followed by a changed file per line
	 */
	public String calculateTransactionDiff(AccurevStream basic, AccurevStream temp1, AccurevStream temp2, AccurevTransaction transaction){

		def String result = ""			

		// create a Directory for every transaction and populate only the changed files at this transaction number
			int i = Integer.parseInt(transaction.id)


			//create a timebased tempstream from the basicstream at the actual transaction number
			temp1.change(basic, i)
			temp2.change(basic, i-1)
			result += transaction.toString() + "\r\n"
			result += temp2.calculateDiff(temp1)

			
			//ad transactioninfo to the resultString
			
			result += "\r\n\r\n"

		return result
	}

	

	/**
	 * calculates all Differences between consecutive transactions of the Stream using Accurevs diff command
	 * @param stream the stream whichs differences shall be calculated
	 * @param tempS1 the temporary Stream to use
	 * @param tempS2 the second temporary Stream to use
	 * @param tStart transactionnumber to start at
	 * @param tEnd transactionnumber to end
	 * @return a String containing all information about the differences in this Stream
	 */
	public String calculateAllDiff(AccurevStream stream, AccurevStream tempS1, AccurevStream tempS2,int tStart, int tEnd){

		String result = ""
		String text
		
		//if tStart is even begin with tempS1 as 'from', else begin with tempS1 as 'to'
		//to start the alternating correctly (see for loop)
		if( (tStart % 2) == 0){
			tempS1.change(stream, tStart)
			tempS2.change(stream,tStart+1)
		} else {
			tempS1.change(stream, tStart+1)
			tempS2.change(stream,tStart)
		}

		//go through the given range and calculate the differences
		for(i in tStart..tEnd){

			//alternate the changed Stream, change it and calculate diff			
			if( (i % 2) == 0){				
				text = tempS1.calculateDiff(tempS2)
				tempS1.change(i+1)
			} else {				
				text = tempS2.calculateDiff(tempS1)
				tempS2.change(i+1)
			}
			//add the result of diff to the returnString. Only if diff provides results.
			if(!text.isEmpty())
			result += "Diffs at transaction ${i}:\r\n" + text + "\r\n"
		}

		return result
	}

	

	/**
	 * 
	 * @param temp Temporary Stream to use for the population
	 * @param basic Stream to populate
	 * @param start Transaction Number to start the population of 'basic' at
	 * @param end Transaction Number to end the population of 'basic' at
	 * @param path Path to store the results at (recent Transaction Number added)
	 */
	public void populateAll(AccurevStream temp, AccurevStream basic, int start, int end, File path){

		String sep = System.getProperty("file.separator")
//		change the temporary Stream to starting transaction number of basicstream
		temp.change(basic, start)
		
//		iterate through every transaction and copy the files of the stream to the a directory of the storepath
		for(i in start..end){
			temp.populateAt( i, new File(path.getPath() + "${sep}${i}") )
		}
		
	}





	
}
